import requests
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.date import DateTrigger
from fastapi import APIRouter, Depends, HTTPException, status, Query, WebSocket, WebSocketDisconnect
from sqlalchemy.orm import Session
from typing import Any, Optional, List, Dict
from app import crud, models, schemas
from app.api import deps
from app.models import BroadcastTask, BroadcastLog
from pydantic.types import UUID4
from datetime import datetime, timedelta

router = APIRouter()
# 初始化AsyncIOScheduler
scheduler = AsyncIOScheduler()
scheduler.start()


# websocket
class ConnectionManager:
    def __init__(self):
        self.active_connections: Dict[str, WebSocket] = {}

    async def connect(self, websocket: WebSocket, user_id: str):
        await websocket.accept()
        self.active_connections[user_id] = websocket

    def disconnect(self, user_id: str):
        if user_id in self.active_connections:
            del self.active_connections[user_id]

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def send_message_to_user(self, message: str, user_id: str):
        if user_id in self.active_connections:
            await self.active_connections[user_id].send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections.values():
            await connection.send_text(message)


manager = ConnectionManager()


@router.websocket("/ws/{user_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: str):
    await manager.connect(websocket, user_id)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.send_personal_message(f"Message text was: {data}", websocket)
    except WebSocketDisconnect:
        manager.disconnect(user_id)


async def send_tts_result(tts_result: str, user_ids: List[str]):
    # 这里可以添加日志记录或打印输出来验证任务执行情况
    print(f"Task executed at {datetime.now()}! TTS result: {tts_result}")
    # 向指定用户发送 TTS 结果
    for user_id in user_ids:
        await manager.send_message_to_user(tts_result, user_id)


@router.post("/", response_model=schemas.BroadcastTaskCreate, summary="新建播报任务")
def create_broadcast_task(
        *,
        db: Session = Depends(deps.get_db),
        task_in: schemas.BroadcastTaskCreate,
) -> Any:
    """
    新建播报任务.
    """
    # 检查是否存在同名任务
    existing_task = crud.broadcast_task.get_by_name(db, name=task_in.name)
    if existing_task:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="系统中已存在具有此名称的任务",
        )
    # 根据任务触发条件进行不同的异常处理
    if task_in.trigger_type == "TIMED_ALERT" and not task_in.warning_time:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="定时预警任务必须指定预警时间",
        )
    elif task_in.trigger_type == "DAILY_NOTIFICATION" and (not task_in.monitor_data or not task_in.condition):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="日常通报任务必须指定监控数据和判断条件",
        )

    # 处理预设文案和新建文案
    if task_in.broadcast_content_ids:
        # 查询预设文案并合并
        presets_content = []
        for broadcast_content_id in task_in.broadcast_content_ids:
            preset = crud.broadcast_presets.get(db, id=broadcast_content_id)
            if preset:
                presets_content.append(preset.content)
        broadcast_content = "\n".join(presets_content)
    elif task_in.broadcast_content:
        broadcast_content = task_in.broadcast_content
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="必须提供预设文案ID列表或新建文案内容",
        )

    # 调用 TTS 算法接口将文本转换为语音
    tts_response = requests.post("http://192.168.1.41:8081/tts", json={
        "text": broadcast_content,
        "format": "mp3"
    })

    if tts_response.status_code != 200 or tts_response.json().get("code") != 1:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="TTS 转换失败"
        )

    tts_result = tts_response.json().get("result")
    # 动态添加 audio_url 属性并赋值
    task_in_dict = task_in.dict()
    task_in_dict['audio_url'] = tts_result

    # 根据触发条件进行不同的处理
    if task_in.trigger_type == "定时预警":
        run_time = task_in.warning_time
        user_ids = task_in.broadcast_target_ids  # 获取播报对象的用户ID列表
        scheduler.add_job(send_tts_result,
                          trigger=DateTrigger(run_date=run_time),
                          args=[tts_result, user_ids])
        print(f"Task scheduled to run at {run_time}")

    elif task_in.trigger_type == "日常通报":
        # 处理日常通报的逻辑 (可以根据具体需求实现)
        # # 日常通报需要在每次触发时记录日志
        pass

    # 有额外添加的audio_url字段，所以使用直接传task_in_dict的方式
    # broadcast_task = crud.broadcast_task.create(db, obj_in=schemas.BroadcastTaskCreate(**task_in_dict))
    broadcast_task = crud.broadcast_task.create(db, obj_in=task_in_dict)

    if task_in.trigger_type == "定时预警":
        # 记录每个播报对象的播报日志
        for target_id in task_in.broadcast_target_ids:
            target = crud.broadcast_target.get(db, id=target_id)
            if target:
                broadcast_log = BroadcastLog(
                    broadcast_task_id=broadcast_task.id,
                    broadcast_time=task_in.warning_time,  # 使用定时预警的时间
                    target_id=target.id,
                    target_name=target.name,
                    target_department=target.department,
                    broadcast_task_name=task_in.name,
                    trigger_type=task_in.trigger_type
                )
                db.add(broadcast_log)
        db.commit()
    elif task_in.trigger_type == "日常通报":
        # # 日常通报需要在每次触发时记录日志
        pass
    return broadcast_task


@router.put("/{id}", response_model=schemas.BroadcastTaskUpdate, summary="编辑播报任务")
def update_broadcast_task(
        *,
        db: Session = Depends(deps.get_db),
        id: UUID4,
        task_in: schemas.BroadcastTaskUpdate,
) -> Any:
    """
    编辑播报任务.
    """
    # 获取要编辑的播报任务
    broadcast_task = crud.broadcast_task.get(db, id=id)
    if not broadcast_task:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="播报任务未找到",
        )

    # 检查是否存在同名但不同 ID 的任务
    existing_task = crud.broadcast_task.get_by_name(db, name=task_in.name)
    if existing_task and existing_task.id != broadcast_task.id:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="系统中已存在具有此名称的任务",
        )

    # 根据任务触发条件进行不同的异常处理
    if task_in.trigger_type == "TIMED_ALERT" and not task_in.warning_time:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="定时预警任务必须指定预警时间",
        )
    elif task_in.trigger_type == "DAILY_NOTIFICATION" and (not task_in.monitor_data or not task_in.condition):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="日常通报任务必须指定监控数据和判断条件",
        )

    task_in_dict = task_in.dict()

    # 如果播报内容发生变化，则调用 TTS 算法接口将文本转换为语音
    if task_in.broadcast_content != broadcast_task.broadcast_content:
        tts_response = requests.post("http://192.168.1.41:8081/tts", json={
            "text": task_in.broadcast_content,
            "format": "mp3"
        })

        if tts_response.status_code != 200 or tts_response.json().get("code") != 1:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="TTS 转换失败"
            )

        tts_result = tts_response.json().get("result")
        task_in_dict['audio_url'] = tts_result
    else:
        task_in_dict['audio_url'] = broadcast_task.audio_url  # 如果内容未修改，保留原有的音频 URL

    # 更新播报任务
    updated_task = crud.broadcast_task.update(db, db_obj=broadcast_task, obj_in=task_in_dict)

    # 根据触发条件进行不同的处理
    if task_in.trigger_type == "TIMED_ALERT":
        run_time = task_in.warning_time
        user_ids = task_in.broadcast_target_ids  # 获取播报对象的用户ID列表
        scheduler.add_job(send_tts_result,
                          trigger=DateTrigger(run_date=run_time),
                          args=[task_in_dict['audio_url'], user_ids])
        print(f"Task rescheduled to run at {run_time}")

        # 记录每个播报对象的播报日志
        for target_id in task_in.broadcast_target_ids:
            target = crud.broadcast_target.get(db, id=target_id)
            if target:
                broadcast_log = BroadcastLog(
                    broadcast_task_id=updated_task.id,
                    broadcast_time=task_in.warning_time,  # 使用定时预警的时间
                    target_id=target.id,
                    target_name=target.name,
                    target_department=target.department,
                    broadcast_task_name=task_in.name,
                    trigger_type=task_in.trigger_type
                )
                db.add(broadcast_log)
        db.commit()
    elif task_in.trigger_type == "DAILY_NOTIFICATION":
        # 处理日常通报的逻辑 (可以根据具体需求实现)
        # 日常通报需要在每次触发时记录日志
        pass

    return updated_task


@router.delete("/{id}", response_model=schemas.BroadcastTask, summary="删除播报任务")
def delete_broadcast_task(
        *,
        db: Session = Depends(deps.get_db),
        id: UUID4,
) -> Any:
    """
    按 ID 删除播报任务.
    """
    # 获取要删除的播报任务
    broadcast_task = crud.broadcast_task.get(db, id=id)
    if not broadcast_task:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="播报任务未找到",
        )
    # 不删日志
    # # 删除与该任务相关的所有播报日志
    # logs = crud.broadcast_log.get_by_task_id(db, task_id=task_id)
    # for log in logs:
    #     db.delete(log)

    # 删除播报任务
    broadcast_task = crud.broadcast_task.remove(db, broadcast_task)

    return broadcast_task


@router.get("/search_tasks", summary="检索播报任务")
def search_tasks(
        search: Optional[str] = None,
        category: Optional[str] = None,
        db: Session = Depends(deps.get_db),
        # with_archived: Optional[bool] = False,
        page_size: int = Query(10, alias="page_size"),  # 每页显示多少条数据
        current_page: int = Query(1, alias="current_page")  # 当前页码
) -> Any:
    """
    通过关键字/分类检索 broadcast_tasks。
    """
    with_archived = False
    # 构建查询对象
    query = db.query(BroadcastTask)
    if search:
        query = query.filter(
            (BroadcastTask.name.ilike(f"%{search}%")) |
            (BroadcastTask.description.ilike(f"%{search}%"))
        )
    if category:
        query = query.filter(BroadcastTask.category == category)
    query = crud.broadcast_task.filter_archivable(query, with_archived)
    # 计算总记录数
    total = query.count()
    # 分页查询
    broadcast_tasks = query.offset((current_page - 1) * page_size).limit(page_size).all()
    result = []
    for broadcast_task in broadcast_tasks:
        updated_at = broadcast_task.updated_at if broadcast_task.updated_at else broadcast_task.created_at
        updated_at_str = updated_at.strftime("%Y年%m月%d日 %H:%M:%S")
        result.append({
            "id": broadcast_task.id,
            "name": broadcast_task.name,
            "category": broadcast_task.category,
            "description": broadcast_task.description,
            "updated_at": updated_at_str,
            "broadcast_target_ids": broadcast_task.broadcast_target_ids,
        })

    return {"total": total, "items": result}


@router.get("/broadcast_targets", summary="人员总列表")
def read_broadcast_targets(
        db: Session = Depends(deps.get_db)
) -> Any:
    """
    检索所有的 broadcast targets 并按部门格式化。
    """
    broadcast_targets = crud.broadcast_target.get_all(db=db)
    departments = {}

    for target in broadcast_targets:
        if target.department not in departments:
            departments[target.department] = []
        departments[target.department].append({
            "id": target.id,
            "name": target.name
        })

    return {"items": departments}


@router.get("/{id}", summary="根据ID查询播报任务详细")
def read_broadcast_task(
        id: UUID4,
        db: Session = Depends(deps.get_db)
) -> Any:
    """
    根据ID查询播报任务详细信息，并按部门格式化播报对象。
    """
    # 查询播报任务详细
    broadcast_task = crud.broadcast_task.get(db=db, id=id)

    if not broadcast_task:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="The broadcast_task with this id does not exist in the system",
        )

    # 获取播报对象ID列表
    broadcast_target_ids = broadcast_task.broadcast_target_ids

    # 根据ID列表查询播报对象
    broadcast_targets = crud.broadcast_target.get_multi_by_ids(db=db, ids=broadcast_target_ids)
    departments = {}

    for target in broadcast_targets:
        if target.department not in departments:
            departments[target.department] = []
        departments[target.department].append({
            "id": target.id,
            "name": target.name
        })
        # 获取总播报次数
    total_broadcasts = db.query(BroadcastLog).filter(BroadcastLog.broadcast_task_id == id).count()
    # 获取最近7天的播报情况
    seven_days_ago = datetime.now() - timedelta(days=7)
    recent_broadcasts = db.query(BroadcastLog).filter(
        BroadcastLog.broadcast_task_id == id,
        BroadcastLog.broadcast_time >= seven_days_ago
    ).all()

    # 按日期统计最近7天的播报次数
    broadcast_count_by_day = {}
    for i in range(7):
        day = (seven_days_ago + timedelta(days=i)).strftime('%Y-%m-%d')
        broadcast_count_by_day[day] = 0

    for log in recent_broadcasts:
        day = log.broadcast_time.strftime('%Y-%m-%d')
        if day in broadcast_count_by_day:
            broadcast_count_by_day[day] += 1
    # 播报触发条件不同，返回给前端的字段不同
    # 定时预警
    if broadcast_task.trigger_type == "定时预警":
        # 返回包含播报任务详细和按部门格式化的播报对象信息
        return {
            "broadcast_task": {
                "id": broadcast_task.id,
                "name": broadcast_task.name,
                "description": broadcast_task.description,
                "trigger_type": broadcast_task.trigger_type,
                "warning_time": broadcast_task.warning_time,
                "priority": broadcast_task.priority,
                "broadcast_content": broadcast_task.broadcast_content,
                "speed": broadcast_task.speed,
                "repeat_frequency": broadcast_task.repeat_frequency,
                "auto_read": broadcast_task.auto_read,
            },
            "broadcast_targets": departments,
            "total_broadcasts": total_broadcasts,
            "recent_broadcasts": broadcast_count_by_day
        }
    else:
        # 返回包含播报任务详细和按部门格式化的播报对象信息
        return {
            "broadcast_task": {
                "id": broadcast_task.id,
                "name": broadcast_task.name,
                "description": broadcast_task.description,
                "trigger_type": broadcast_task.trigger_type,
                "monitor_data": broadcast_task.monitor_data,
                "condition": broadcast_task.condition,
                "broadcast_content": broadcast_task.broadcast_content,
                "speed": broadcast_task.speed,
                "repeat_frequency": broadcast_task.repeat_frequency,
                "auto_read": broadcast_task.auto_read,
            },
            "broadcast_targets": departments,
            "total_broadcasts": total_broadcasts,
            "recent_broadcasts": broadcast_count_by_day
        }
